from datetime import datetime, timedelta
from typing import Optional

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.crud.base import CRUDBase
from app.models.verification_code import VerificationCode, VerificationPurpose
from app.schemas.user import SmsCodeRequest


class CRUDVerificationCode(CRUDBase[VerificationCode, SmsCodeRequest, SmsCodeRequest]):
    async def create_code(
        self,
        db: AsyncSession,
        *,
        phone: str,
        purpose: VerificationPurpose,
        code: str,
        expire_minutes: int = 10,
    ) -> VerificationCode:
        expires_at = datetime.utcnow() + timedelta(minutes=expire_minutes)
        db_obj = VerificationCode(
            phone=phone,
            code=code,
            purpose=purpose,
            expires_at=expires_at,
        )
        db.add(db_obj)
        await db.flush()
        await db.refresh(db_obj)
        return db_obj

    async def verify_code(
        self,
        db: AsyncSession,
        *,
        phone: str,
        purpose: VerificationPurpose,
        code: str,
    ) -> Optional[VerificationCode]:
        result = await db.execute(
            select(VerificationCode)
            .filter(
                VerificationCode.phone == phone,
                VerificationCode.purpose == purpose,
                VerificationCode.code == code,
                VerificationCode.is_used.is_(False),
                VerificationCode.expires_at >= datetime.utcnow(),
            )
            .order_by(VerificationCode.created_at.desc())
        )
        return result.scalars().first()

    async def mark_used(self, db: AsyncSession, *, verification_code: VerificationCode) -> None:
        verification_code.is_used = True
        db.add(verification_code)
        await db.flush()


verification_code = CRUDVerificationCode(VerificationCode)
